package com.huawei.app.httpapi;

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.text.Normalizer;
import java.text.Normalizer.Form;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;

import com.alibaba.fastjson.JSONObject;
import com.huawei.app.demo.util.LogUtils;

import okhttp3.Call;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;

/**
 * http请求工具类
 */
public class HttpClientUtil {

    private static final String TAG = HttpClientUtil.class.getSimpleName();
    private static final int CALL_IMEOUT = 5000;
    private static final int CONNECTT_IMEOUT = 5000;
    private static final int READ_IMEOUT = 5000;
    private static final int WRITE_TIMEOUT = 30000;

    private static OkHttpClient httpclient = null;
    public static String sessionId;

    private static OkHttpClient getHttpClient() {
        if (null == httpclient) {
            synchronized (HttpClientUtil.class) {
                if (null == httpclient) {
                    httpclient = init();
                }
            }
        }
        return httpclient;
    }

    /**
     * 初始化
     * @return
     */
    private static OkHttpClient init() {
        OkHttpClient mClient = null;
        try {
            MyTrustManager trustManager = new MyTrustManager();
            SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
            sslContext.init(null, new TrustManager[]{trustManager}, null);

            mClient = new OkHttpClient.Builder()
                    .callTimeout(CALL_IMEOUT, TimeUnit.MILLISECONDS)
                    .connectTimeout(CONNECTT_IMEOUT, TimeUnit.MILLISECONDS)
                    .readTimeout(READ_IMEOUT, TimeUnit.MILLISECONDS)
                    .writeTimeout(WRITE_TIMEOUT, TimeUnit.MILLISECONDS)
                    .hostnameVerifier(new IgnoreHostnameVerifier())
                    .sslSocketFactory(sslContext.getSocketFactory(), trustManager)
                    .build();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        return mClient;
    }

    /**
     * GET请求
     * @param uri
     * @param headerMap
     * @return
     */
    public static JSONObject get(String uri, Map<String, String> headerMap) {
        return excute(uri, "GET", null, headerMap);
    }

    /**
     * DELETE请求
     * @param uri
     * @param headerMap
     * @return
     */
    public static JSONObject delete(String uri, Map<String, String> headerMap) {
        return excute(uri, "DELETE", null, headerMap);
    }

    /**
     * PUT请求
     * @param uri
     * @param bodyJsonObj
     * @param headerMap
     * @return
     */
    public static JSONObject put(String uri, JSONObject bodyJsonObj, Map<String, String> headerMap) {
        return excute(uri, "PUT", bodyJsonObj, headerMap);
    }

    /**
     * POST请求
     * @param uri
     * @param bodyJsonObj
     * @param headerMap
     * @return
     */
    public static JSONObject post(String uri, JSONObject bodyJsonObj, Map<String, String> headerMap) {
        return excute(uri, "POST", bodyJsonObj, headerMap);
    }

    /**
     * 执行HTTP请求
     * @param uri
     * @param methodType
     * @param bodyJsonObj
     * @param headerMap
     * @return
     */
    public static JSONObject excute(
            String uri, String methodType, JSONObject bodyJsonObj, Map<String, String> headerMap) {
        uri = Normalizer.normalize(uri, Form.NFKC);
        Request httpRequest = getHttpRequest(uri, methodType, headerMap, bodyJsonObj);

        Response response = null;
        try {
            if (isNormalUrl(uri)) {
                LogUtils.getInstance().d(TAG, "execute http api, uri=" + uri + ", request=" + requestToString(httpRequest));
            }

            Call call = getHttpClient().newCall(httpRequest);
            response = call.execute();
            if (!response.isSuccessful()) {
                LogUtils.getInstance().e(TAG, "execute http api failed, uri=" + uri + ", response headers=" + responseToString(response));
                return null;
            }

            if (isNormalUrl(uri)) {
                LogUtils.getInstance().d(TAG, "execute http api, uri=" + uri + ", response headers=" + responseToString(response));
            }
            if (isNeedParseHeader(uri)) {
                sessionId = response.header("Set-Cookie").split(";")[0];
                LogUtils.getInstance().d(TAG, "execute http api, uri=" + uri + ", response body=" + response.body().string());
            } else {
                if (isDownloadUrl(uri)) {
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("success", 1);
                    jsonObject.put("data", response.body().bytes());
                    return jsonObject;
                }

                String bodyStr = response.body().string();
                if (bodyStr != null && !bodyStr.trim().isEmpty()) {
                    if (isNormalUrl(uri)) {
                        LogUtils.getInstance().d(TAG, "execute http api, uri=" + uri + ", response body=" + bodyStr);
                    }

                    JSONObject jsonObject = JSONObject.parseObject(bodyStr);
                    return jsonObject;
                }
                LogUtils.getInstance().e(TAG, "execute http api failed, uri=" + uri + ", bodyStr is null or empty.");
            }
        } catch (Exception e) {
            LogUtils.getInstance().e(TAG, "execute http api failed, uri=" + uri + ", ", e);
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return null;
    }

    private static Request getHttpRequest(
            String uri, String methodType, Map<String, String> headers, JSONObject jsonBody) {
        Request httpRequest = null;
        Request.Builder builder = new Request.Builder().url(uri);

        // 添加headers
        if (headers != null && !headers.isEmpty()) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                builder.header(entry.getKey(), entry.getValue());
            }
        }
        if (HttpClientUtil.sessionId != null) {
            builder.header("Cookie", HttpClientUtil.sessionId);
        }
        builder.header("Content-type", "application/json; charset=UTF-8");

        if ("DELETE".equalsIgnoreCase(methodType)) {
            httpRequest = builder.delete().build();
        } else if ("POST".equalsIgnoreCase(methodType)) {
            httpRequest = builder.post(createRequestBody(jsonBody)).build();
        } else if ("PUT".equalsIgnoreCase(methodType)) {
            httpRequest = builder.put(createRequestBody(jsonBody)).build();
        } else {
            httpRequest = builder.get().build();
        }
        return httpRequest;
    }

    private static RequestBody createRequestBody(JSONObject jsonBody) {
        MediaType jsonType = MediaType.parse("application/json; charset=utf-8");
        String jsonStr = "";
        if (jsonBody != null) {
            jsonStr = jsonBody.toString().trim();
        }
        RequestBody body = RequestBody.create(jsonStr, jsonType);
        return body;
    }

    private static boolean isNeedParseHeader(String uri) {
        return uri.contains("WEB_RequestSessionIDAPI") || uri.contains("WEB_ChangeSessionIDAPI");
    }

    private static String requestToString(Request httpRequest) {
        StringBuilder sb = new StringBuilder();
        sb.append(System.lineSeparator());
        sb.append(httpRequest.method()).append(" ").append(httpRequest.url()).append(System.lineSeparator());
        sb.append(httpRequest.headers()).append(System.lineSeparator());
        try
        {
            Buffer buffer = new Buffer();
            httpRequest.body().writeTo(buffer);
            sb.append(buffer.readUtf8());
        } catch (Exception e) {
            //
        }
        return sb.toString();
    }

    private static String responseToString(Response httpResponse) {
        StringBuilder sb = new StringBuilder();
        sb.append(System.lineSeparator());
        sb.append("http status ").append(httpResponse.code()).append(System.lineSeparator());
        sb.append(httpResponse.headers()).append(System.lineSeparator());
        return sb.toString();
    }

    private static boolean isDownloadUrl(String uri) {
        return uri.contains("/v1/ai/face-detection/picture");
    }

    private static boolean isNormalUrl(String uri) {
        return !uri.contains("WEB_GetMailboxDataAPI");
    }

}
